package org.lightweightimageviewer.liv;

import javax.swing.*;

import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.io.File;

import static org.lightweightimageviewer.liv.UserPreferences.*;

/**
 * Created by IntelliJ IDEA. 
 * TODO: 
 * Create Preferences GUI 
 * Link Preferences GUI to menu. 
 * Add Zoom
 * 
 * @author Steven Boscarine Date: Dec 14, 2007 1:54:17 PM
 */
public class ImgViewer extends JFrame {
	private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ImgViewer.class);
	private LiImage current;
	private final StatusBar status;
	private final JComponent img = new ImgPanel();
	private final ImageCache cache;
	private boolean isSlideshow = false;
	//stupid hack
	//private boolean isResize = false;
	private final Dimension maxSize;
	
	public static void main(String[] args) {
		// Validation: Did they pass an argument?
		if (args == null || args.length == 0) {
			System.err.println("Please enter an image name.");
			return;
		}
		final File fileName = new File(args[0]); // needs to be final to be accessed from run()
		// Validation: Did they provide an invalid directory or file?
		if (!fileName.exists()) {
			System.err.println("Cannot find " + fileName.getAbsolutePath() + " is it a valid directory or file?");
			return;
		}
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new ImgViewer(fileName);
			}
		});
	}

	private ImgViewer(File dir) {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);			//standard Swing boilerplate.
		final MouseHandler mouseHandler = new MouseHandler();
		
		JMenu menu = new JMenu("Additional Functions");
		final JMenuBar menuBar = new JMenuBar();
		menuBar.add(menu);
		buildMenu(menu);
		setJMenuBar(menuBar);
		//create image cache/repository.
		cache = new ImageCache(dir);
		
		current = cache.getCurrent();
		add(img, BorderLayout.CENTER);
		status = new StatusBar(cache.getTotal());
		add(status, BorderLayout.SOUTH);
		addMouseWheelListener(mouseHandler);
		// Set the component to show the popup menu
		addMouseListener(mouseHandler);
		addKeyListener(new KL());
		addComponentListener(new ComponentHandler());
		updateInformation();
		
		
		//InputMap im = img.getInputMap();
		
		setExtendedState(JFrame.MAXIMIZED_BOTH);
		setVisible(true);
		maxSize = getSize();
		ImageResizer.init(maxSize);
		pack(); // set to correct size
	}

	private static void buildMenu(JComponent parent) {
		parent.add(new JMenuItem("change directory"));
		parent.add(new JMenuItem("slideshow"));
		parent.add(new JMenuItem("settings"));
	}

	private final void update() {
		updateInformation();
		updateSize();
	}

	/**
	 * Wrapper for Swing code to update window size.  
	 */
	private void updateSize() {
		SwingUtilities.updateComponentTreeUI(img);
		pack(); // resize
	}

	private void resizeWindow(Dimension newSize){
		current.resize(newSize);
		updateSize();
	}
	
	private final void updateInformation() {
		setTitle(current.getFileName());
		status.update(current);
	}

	private final class ImgPanel extends JComponent {
		@Override
		public void paint(Graphics g) {
			g.drawImage(current.getImage(), 0, 0, null);
		}

		@Override
		public Dimension getPreferredSize() {
			return new Dimension(current.getImage().getWidth(), current.getImage().getHeight());
		}

		private static final long serialVersionUID = 1L;
	}

	private final class Slideshow implements Runnable {
		@Override
		public void run() {
			while (isSlideshow) {
				current = cache.getNextSlideshowImage();
				update();
				try {
					Thread.sleep(SLIDESHOW_INCREMENT);
				} catch (InterruptedException e) {
					throw new RuntimeException(e);
				}
			}
		}
	}

	private class ComponentHandler extends ComponentAdapter{
		@Override
		public void componentResized(ComponentEvent e) {
			logger.info(getSize() + " component=  " + e.getComponent());
			// TODO Auto-generated method stub
//			resizeWindow(getSize());
			//super.componentResized(e);
		}
	}
	private class MouseHandler extends MouseAdapter {
		final JPopupMenu contextMenu = new JPopupMenu();
		MouseHandler() {
			buildMenu(contextMenu);
		}

		/**	Actual business logic.  All it does is render the menu.	*/
		private void handleEvent(MouseEvent evt) {
			if (evt.isPopupTrigger()) {
				contextMenu.show(evt.getComponent(), evt.getX(), evt.getY());
			}
		}
		@Override
		public void mousePressed(MouseEvent evt) {
			handleEvent(evt);
		}


		@Override
		public void mouseReleased(MouseEvent evt) {
			handleEvent(evt);
		}

		@Override
		public void mouseWheelMoved(MouseWheelEvent e) {
			current = (e.getWheelRotation() > 0) ? cache.getNext() : cache.getPrevious();
			((ImgViewer) e.getSource()).update();
		}
	}

	private class KL extends KeyAdapter {
		@Override
		public void keyPressed(KeyEvent e) {
			final int keyCode = e.getKeyCode();
			final double SCALE = 1.2;
			
			if (previousImage.contains(keyCode)) {
				current = cache.getPrevious();
				update();
			} else if (nextImage.contains(keyCode)) {
				current = cache.getNext();
				update();
			} else if (zoomIn.contains(keyCode) || zoomOut.contains(keyCode)) {
				final Dimension old = new Dimension(current.getImage().getWidth(), current.getImage().getHeight());
				double factor = zoomIn.contains(keyCode)? SCALE : (1/SCALE);
				final int w = (int)(old.getWidth()*factor);
				final int h = (int)(old.getHeight()*factor);
				final Dimension newSize = new Dimension(w, h);
				logger.debug(old + " " + newSize);
				resizeWindow(newSize);
			} else if (slideshow.contains(keyCode)) {
				isSlideshow = !isSlideshow;
				Thread ss = new Thread(new Slideshow());
				ss.start();
			} else {
				logger.debug("Unrecognized key sequence: " + keyCode);
			}
		}
	}

	private static final long serialVersionUID = 1L;
}